/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/***************************************************************************
 * Name: ReverseIterator.h
 *
 * Purpose: reverse iterator implementation
 *
 * Developer:
 *   wen.gu , 2020-04-09
 *
 * TODO:
 *
 ***************************************************************************/

#ifndef _ARA_CORE_REVERSE_ITERATOR_H__
#define _ARA_CORE_REVERSE_ITERATOR_H__
/******************************************************************************
 **    INCLUDES
 ******************************************************************************/

#include <iterator>


/******************************************************************************
 **    MACROS
 ******************************************************************************/
#if __cplusplus > 201402L
#define _ARALIBCXX17_CONSTEXPR constexpr
#else
#define _ARALIBCXX17_CONSTEXPR
#endif

/******************************************************************************
 **    TYPE DEFINITIONS
 ******************************************************************************/
namespace ara
{
namespace core
{
/******************************************************************************
 **    CLASSES/FUNCTIONS DEFINITIONS
 ******************************************************************************/

// 24.4.1 Reverse iterators
/**
 *  Bidirectional and random access iterators have corresponding reverse
 *  %iterator adaptors that iterate through the data structure in the
 *  opposite direction.  They have the same signatures as the corresponding
 *  iterators.  The fundamental relation between a reverse %iterator and its
 *  corresponding %iterator @c i is established by the identity:
 *  @code
 *      &*(ReverseIterator(i)) == &*(i - 1)
 *  @endcode
 *
 *  <em>This mapping is dictated by the fact that while there is always a
 *  pointer past the end of an array, there might not be a valid pointer
 *  before the beginning of an array.</em> [24.4.1]/1,2
 *
 *  Reverse iterators can be tricky and surprising at first.  Their
 *  semantics make sense, however, and the trickiness is a side effect of
 *  the requirement that the iterators must be safe.
*/
template<typename _Iterator>
  class ReverseIterator
  : public std::iterator<typename std::iterator_traits<_Iterator>::iterator_category,
            typename std::iterator_traits<_Iterator>::value_type,
            typename std::iterator_traits<_Iterator>::difference_type,
            typename std::iterator_traits<_Iterator>::pointer,
                    typename std::iterator_traits<_Iterator>::reference>
  {
  protected:
    _Iterator current;

    typedef std::iterator_traits<_Iterator>		__traits_type;

  public:
    typedef _Iterator					iterator_type;
    typedef typename __traits_type::difference_type	difference_type;
    typedef typename __traits_type::pointer		pointer;
    typedef typename __traits_type::reference		reference;

    /**
     *  The default constructor value-initializes member @p current.
     *  If it is a pointer, that means it is zero-initialized.
    */
    // _GLIBCXX_RESOLVE_LIB_DEFECTS
    // 235 No specification of default ctor for ReverseIterator
    _ARALIBCXX17_CONSTEXPR ReverseIterator() : current() { }

    /**
     *  This %iterator will move in the opposite direction that @p x does.
    */
    explicit _ARALIBCXX17_CONSTEXPR ReverseIterator(iterator_type __x) : current(__x) { }

    /**
     *  The copy constructor is normal.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator(const ReverseIterator& __x)
    : current(__x.current) { }

    /**
     *  A %ReverseIterator across other types can be copied if the
     *  underlying %iterator can be converted to the type of @c current.
    */
    template<typename _Iter>
  _ARALIBCXX17_CONSTEXPR ReverseIterator(const ReverseIterator<_Iter>& __x)
  : current(__x.base()) { }

    /**
     *  @return  @c current, the %iterator used for underlying work.
    */
    _ARALIBCXX17_CONSTEXPR iterator_type base() const
    { return current; }

    /**
     *  @return  A reference to the value at @c --current
     *
     *  This requires that @c --current is dereferenceable.
     *
     *  @warning This implementation requires that for an iterator of the
     *           underlying iterator type, @c x, a reference obtained by
     *           @c *x remains valid after @c x has been modified or
     *           destroyed. This is a bug: http://gcc.gnu.org/PR51823
    */
    _ARALIBCXX17_CONSTEXPR reference operator*() const
    {
        _Iterator __tmp = current;
        return *--__tmp;
    }

    /**
     *  @return  A pointer to the value at @c --current
     *
     *  This requires that @c --current is dereferenceable.
    */
    _ARALIBCXX17_CONSTEXPR pointer operator->() const
    { return &(operator*()); }

    /**
     *  @return  @c *this
     *
     *  Decrements the underlying iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator& operator++()
    {
        --current;
        return *this;
    }

    /**
     *  @return  The original value of @c *this
     *
     *  Decrements the underlying iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator operator++(int)
    {
        ReverseIterator __tmp = *this;
        --current;
        return __tmp;
    }

    /**
     *  @return  @c *this
     *
     *  Increments the underlying iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator& operator--()
    {
        ++current;
        return *this;
    }

    /**
     *  @return  A ReverseIterator with the previous value of @c *this
     *
     *  Increments the underlying iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator operator--(int)
    {
        ReverseIterator __tmp = *this;
        ++current;
        return __tmp;
    }

    /**
     *  @return  A ReverseIterator that refers to @c current - @a __n
     *
     *  The underlying iterator must be a Random Access Iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator operator+(difference_type __n) const
    { return ReverseIterator(current - __n); }

    /**
     *  @return  *this
     *
     *  Moves the underlying iterator backwards @a __n steps.
     *  The underlying iterator must be a Random Access Iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator& operator+=(difference_type __n)
    {
        current -= __n;
        return *this;
    }

    /**
     *  @return  A ReverseIterator that refers to @c current - @a __n
     *
     *  The underlying iterator must be a Random Access Iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator operator-(difference_type __n) const
    { return ReverseIterator(current + __n); }

    /**
     *  @return  *this
     *
     *  Moves the underlying iterator forwards @a __n steps.
     *  The underlying iterator must be a Random Access Iterator.
    */
    _ARALIBCXX17_CONSTEXPR ReverseIterator& operator-=(difference_type __n)
    {
        current += __n;
        return *this;
    }

    /**
     *  @return  The value at @c current - @a __n - 1
     *
     *  The underlying iterator must be a Random Access Iterator.
    */
    _ARALIBCXX17_CONSTEXPR reference operator[](difference_type __n) const
    { return *(*this + __n); }
};

//@{
/**
 *  @param  __x  A %ReverseIterator.
 *  @param  __y  A %ReverseIterator.
 *  @return  A simple bool.
 *
 *  Reverse iterators forward many operations to their underlying base()
 *  iterators.  Others are implemented in terms of one another.
 *
*/
template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator==(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return __x.base() == __y.base();
}

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator<(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return __y.base() < __x.base();
}

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator!=(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return !(__x == __y);
}

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator>(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return __y < __x;
}

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator<=(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return !(__y < __x);
}

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR bool operator>=(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return !(__x < __y);
}

// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 280. Comparison of ReverseIterator to const ReverseIterator.
template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator==(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return __x.base() == __y.base();
}

template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator<(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return __y.base() < __x.base();
}

template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator!=(const ReverseIterator<_IteratorL>& __x,  const ReverseIterator<_IteratorR>& __y)
{
    return !(__x == __y);
}

template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator>(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return __y < __x;
}

template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator<=(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return !(__y < __x);
}

template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR bool operator>=(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return !(__x < __y);
}
//@}

#if __cplusplus < 201103L
template<typename _Iterator>
inline typename ReverseIterator<_Iterator>::difference_type operator-(const ReverseIterator<_Iterator>& __x, const ReverseIterator<_Iterator>& __y)
{
    return __y.base() - __x.base();
}

template<typename _IteratorL, typename _IteratorR>
inline typename ReverseIterator<_IteratorL>::difference_type operator-(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y)
{
    return __y.base() - __x.base();
}
#else
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 685. ReverseIterator/move_iterator difference has invalid signatures
template<typename _IteratorL, typename _IteratorR>
inline _ARALIBCXX17_CONSTEXPR auto operator-(const ReverseIterator<_IteratorL>& __x, const ReverseIterator<_IteratorR>& __y) -> decltype(__y.base() - __x.base())
{
    return __y.base() - __x.base();
}
#endif

template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR ReverseIterator<_Iterator> operator+(typename ReverseIterator<_Iterator>::difference_type __n, const ReverseIterator<_Iterator>& __x)
{
    return ReverseIterator<_Iterator>(__x.base() - __n);
}

#if __cplusplus >= 201103L
// Same as C++14 make_ReverseIterator but used in C++03 mode too.
template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR ReverseIterator<_Iterator> __make_ReverseIterator(_Iterator __i)
{
    return ReverseIterator<_Iterator>(__i);
}

# if __cplusplus > 201103L
#  define __cpp_lib_make_ReverseIterator 201402

// _GLIBCXX_RESOLVE_LIB_DEFECTS
// DR 2285. make_ReverseIterator
/// Generator function for ReverseIterator.
template<typename _Iterator>
inline _ARALIBCXX17_CONSTEXPR ReverseIterator<_Iterator> make_ReverseIterator(_Iterator __i)
{
    return ReverseIterator<_Iterator>(__i);
}
# endif /** end of __cplusplus > 201103L */
#endif /** end of __cplusplus >= 201103L */



#if __cplusplus >= 201103L
template<typename _Iterator>
auto __NiterBase(ReverseIterator<_Iterator> __it) -> decltype(__make_ReverseIterator(__niter_base(__it.base())))
{
    return __make_ReverseIterator(__niter_base(__it.base()));
}

//template<typename _Iterator>
//struct __is_move_iterator<ReverseIterator<_Iterator> >
//   :__is_move_iterator<_Iterator>
//  { };

template<typename _Iterator>
auto __MiterBase(ReverseIterator<_Iterator> __it) -> decltype(__make_ReverseIterator(__miter_base(__it.base())))
 { return __make_ReverseIterator(__miter_base(__it.base()));
 }
#endif /** end of __cplusplus >= 201103L */

} /** namespace core */
} /** namespace ara */
#endif /** !_ARA_CORE_REVERSE_ITERATOR_H__ */


